
#include "stdafx.h"
#ifndef _NOSERVER_

#include "ClientThread.h"
#include "PolicyDelegate.h"
#include "Constant.h"
#include "HookFunc.h"

extern void IDLE();

void CClientThread::init(SOCKET sock, TICK tk)
{
	pData = nullptr; stopReason = StopThread_Reason::KeepRunning;
	int peerLen = sizeof(sockaddr_in); getpeername(sock, (sockaddr *)&addr, &peerLen);
	connectTk = tk; cltSock = sock;
#ifndef _WEBKIT_NEW
	preStatus = 0;
#endif
}

void CClientThread::stop(StopThread_Reason reason, bool waitTillEnd, bool haveLocked)
{
	if (!haveLocked) lock.Lock();
	stopReason = reason;
	lock.Unlock();
	if (!waitTillEnd) return;
	for (;; IDLE())
	{
		if (!lock.TestLock()) continue;
		bool bRet = CheckThread(hThread, hThreadRunning);
		lock.Unlock();
		if (!bRet) break;
	}
}

void CClientThread::ClientStarted(CPolicyDelegate *caller)
{
	lock.Lock();
	pData = new CPolicyServerClt(caller);
	lock.Unlock();
#ifdef _WEBKIT_NEW
	((CPolicyServerClt*)pData)->OnClientConnected(this);
#endif
}

void CClientThread::ClientStoped(StopThread_Reason reason)
{
#ifdef _WEBKIT_NEW
	((CPolicyServerClt*)pData)->OnClientDisconnected(this, reason);
#endif
	lock.Lock();
	CPolicyServerClt *pSrvClt = (CPolicyServerClt*)pData;
	if (pSrvClt) delete pSrvClt;
	pData = nullptr;
	lock.Unlock();
}

void CClientThread::ClientDataRecved(byte * data, intptr_t dataLength)
{
	lock.Lock();
	CPolicyServerClt *pSrvClt = (CPolicyServerClt*)pData;
	if (pSrvClt)
	{
		StopThread_Reason reason = pSrvClt->ClientDataRecved(this, data, dataLength);
		if (reason != KeepRunning)
		{
			stop(reason, false, true); return;
		}
	}
	lock.Unlock();
}

void CClientThread::ClientThreadIdle()
{
	lock.Lock();
	CPolicyServerClt *pSrvClt = (CPolicyServerClt*)pData;
	if (pSrvClt)
	{
		StopThread_Reason reason = pSrvClt->ClientThreadIdle(this);
		if (reason != KeepRunning)
		{
			stop(reason, false, true); return;
		}
	}
	lock.Unlock();
}

DWORD CClientThread::Thread_Client(IServerSocketDelegate *caller)
{
	byte recvBuf[4096]; StopThread_Reason reason = StopThread_Reason::KeepRunning;
	for (caller->ClientStarted(this);; Sleep(10))
	{
		lock.Lock();
		reason = stopReason;
		lock.Unlock();
		if (reason != StopThread_Reason::KeepRunning) break;
		intptr_t r = FUNC_testSock(cltSock, true);
		if (r < 0)
		{
			stop(StopThread_Reason::ListenFail, false); continue;
		}
		else if (r > 0)
		{
			intptr_t ln = FUNC_recv(cltSock, (char*)recvBuf, sizeof(recvBuf), 0);
			if (ln <= 0)
			{
				stop(StopThread_Reason::RecvFail, false); continue;
			}
			caller->ClientDataRecved(this, recvBuf, ln);
		}	//r>0
		caller->ClientThreadIdle(this);
	}
	caller->ClientStoped(this, stopReason);
	shutdown(cltSock, SD_BOTH); closesocket(cltSock); cltSock = 0;
	lock.Lock();
	hThreadRunning = false;
	lock.Unlock();
	return 0;
}

#ifndef _WEBKIT_NEW
const stPreData *CClientThread::getPreData() const
{
	return preStatus == 2 ? &preData : nullptr;
}

StopThread_Reason CClientThread::checkPreData(CWebPacketHead *pHead)
{
	const stPreData *pPre = pHead->getPreData();
	switch (preStatus)
	{
	case 0:
		preStatus = (pPre == nullptr) ? 1 : 2;
		if (preStatus == 2) memcpy_s(&preData, sizeof(stPreData), pPre, sizeof(stPreData));
		return StopThread_Reason::KeepRunning;
	case 1:
		return (pPre == nullptr) ? StopThread_Reason::KeepRunning : StopThread_Reason::ForceOffline;
	default:
		return (pPre != nullptr && memcmp(&preData, pPre, sizeof(stPreData)) == 0) ?
			StopThread_Reason::KeepRunning : StopThread_Reason::ForceOffline;
	}
}
#endif	//_WEBKIT_NEW

#endif
